package com.groupware.board.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import com.groupware.board.model.BoardCommentModel;
import com.groupware.board.model.BoardModel;
import com.groupware.board.service.BoardService;

@Controller
@RequestMapping("/board")
public class BoardController {
	// DI
	private ApplicationContext context = new ClassPathXmlApplicationContext("/config/applicationContext.xml");
	private BoardService boardService = (BoardService) context.getBean("boardService");
	//
	// * User variable
	// article, page variables
	private int currentPage = 1;
	private int showArticleLimit = 10; // change value if want to show more articles by one page
	private int showPageLimit = 10; // change value if want to show more page links
	private int startArticleNum = 0;
	private int endArticleNum = 0;
	private int totalNum = 0;
	//
	// file upload path
	private String uploadPath = "C:\\dev\\workspace\\sts\\Groupware-Project\\src\\main\\webapp\\files\\";
	//
	//
	
	
	@RequestMapping("/list.do")
	public ModelAndView boardList(HttpServletRequest request, HttpServletResponse response){
		
		String type = null;
		String keyword = null;	
		
		// set variables from request parameter
		if(request.getParameter("page") == null || request.getParameter("page").trim().isEmpty() || request.getParameter("page").equals("0")) {
			currentPage = 1;
		} else {
			currentPage = Integer.parseInt(request.getParameter("page"));
		}
		
		if(request.getParameter("type") != null){
			type = request.getParameter("type").trim();
		}
		
		if(request.getParameter("keyword") != null){
			keyword = request.getParameter("keyword").trim();
		}
		//
		
		// expression article variables value
		totalNum = boardService.getTotalNum();
		//
		
		// get boardList and get page html code
		List<BoardModel> boardList;
		if(type != null && keyword != null){
			totalNum = boardService.getSearchTotalNum(type, keyword);
			startArticleNum = totalNum - ((currentPage - 1) * showArticleLimit);
			endArticleNum = startArticleNum - (showArticleLimit -1);
			
			boardList = boardService.searchArticle(type, keyword, endArticleNum, startArticleNum);
		} else {
			totalNum = boardService.getTotalNum();
			startArticleNum = totalNum - ((currentPage - 1) * showArticleLimit);
			endArticleNum = startArticleNum - (showArticleLimit -1);
			boardList = boardService.getBoardList(endArticleNum, startArticleNum);
			totalNum = boardService.getTotalNum();
		}
		StringBuffer pageHtml = getPageHtml(currentPage, totalNum, showArticleLimit, showPageLimit, type, keyword);
		//
		
		ModelAndView mav = new ModelAndView();
		mav.addObject("boardList", boardList);
		mav.addObject("pageHtml", pageHtml);
		mav.setViewName("/board/list");
		
		return mav;
	}
	
	// A method for Creating page html code
	private StringBuffer getPageHtml(int currentPage, int totalNum, int showArticleLimit, int showPageLimit, String type, String keyword) {
		StringBuffer pageHtml = new StringBuffer();
		int startPage = 0;
		int lastPage = 0;
		// expression page variables
		startPage = ((currentPage-1) / showPageLimit) * showPageLimit + 1;
		lastPage = startPage + showPageLimit - 1;
		
		if(lastPage > totalNum / showArticleLimit) {
			lastPage = (totalNum / showArticleLimit) + 1;
		}
		//
		
		// create page html code
		// if: when no search	
		if(type == null && keyword == null){			
			if(currentPage == 1){
				pageHtml.append("<span>");
			} else {
				pageHtml.append("<span><a href=\"list.do?page=" + (currentPage-1) + "\"><이전</a>&nbsp;&nbsp;");
			}
			
			for(int i = startPage ; i <= lastPage ; i++) {
				if(i == currentPage){
					pageHtml.append(".&nbsp;<strong>");
					pageHtml.append("<a href=\"list.do?page=" +i + "\" class=\"page\">" + i + "</a>");
					pageHtml.append("&nbsp;</strong>");
				} else {
					pageHtml.append(".&nbsp;<a href=\"list.do?page=" +i + "\" class=\"page\">" + i + "</a>&nbsp;");
				}
				
			}
			if(currentPage == lastPage){
				pageHtml.append(".</span>");
			} else {
				pageHtml.append(".&nbsp;&nbsp;<a href=\"list.do?page=" + (currentPage+1) + "\">다음></a></span>");
			}
		//
		// else: when search
		} else {			
			if(currentPage == 1){
				pageHtml.append("<span>");
			} else {
				pageHtml.append("<span><a href=\"list.do?page=" + (currentPage-1) + "&type=" + type + "&keyword=" + keyword + "\"><이전</a>&nbsp;&nbsp;");
			}
			
			for(int i = startPage ; i <= lastPage ; i++) {
				if(i == currentPage){
					pageHtml.append(".&nbsp;<strong>");
					pageHtml.append("<a href=\"list.do?page=" +i + "&type=" + type + "&keyword=" + keyword + "\" class=\"page\">" + i + "</a>&nbsp;");
					pageHtml.append("&nbsp;</strong>");
				} else {
					pageHtml.append(".&nbsp;<a href=\"list.do?page=" +i + "&type=" + type + "&keyword=" + keyword + "\" class=\"page\">" + i + "</a>&nbsp;");
				}
				
			}
			if(currentPage == lastPage){
				pageHtml.append("</span>");
			} else {
				pageHtml.append(".&nbsp;&nbsp;<a href=\"list.do?page=" + (currentPage+1) + "&type=" + type + "&keyword=" + keyword + "\">다음></a></span>");
			}
		}
		//		
		return pageHtml;
	}
	
	@RequestMapping("/view.do")
	public ModelAndView boardView(HttpServletRequest request, HttpSession session) throws UnknownHostException{
		int idx = Integer.parseInt(request.getParameter("idx"));		
		BoardModel board = boardService.getOneArticle(idx); // get selected article model
		String regip = InetAddress.getLocalHost().getHostAddress();
		
		if(!board.getWriterId().equals((String) session.getAttribute("userId"))){
			boardService.updateHitcount(board.getHitcount()+1, idx); // update hitcount
		}
		
		List<BoardCommentModel> commentList = boardService.getCommentList(idx); // get comment list
		
		ModelAndView mav = new ModelAndView();
		mav.addObject("board", board);
		mav.addObject("commentList", commentList);
		mav.setViewName("/board/view");
		return mav;
	}
	
	@RequestMapping("/write.do")
	public String boardWrite(@ModelAttribute("BoardModel") BoardModel boardModel){
		return "/board/write";
	}
	
	@RequestMapping(value="/write.do", method=RequestMethod.POST)
	public String boardWriteProc(@ModelAttribute("BoardModel") BoardModel boardModel, MultipartHttpServletRequest request) throws UnknownHostException{
		
		// get upload file
		MultipartFile file = request.getFile("file");
		String fileName = file.getOriginalFilename();
		File uploadFile = new File(uploadPath + fileName);
		System.out.println(uploadFile);
		// when file exists as same name
		if(uploadFile.exists()){
			fileName = new Date().getTime() + fileName;
			uploadFile = new File(uploadPath + fileName);
		}
		System.out.println(uploadFile);
		// save upload file to uploadPath
		try {
			file.transferTo(uploadFile);
		} catch (Exception e) {
			
		}
		
		//
		// new line code change to <br /> tag	
		String content =  boardModel.getContent().replaceAll("\r\n", "<br />");		
		String regip = InetAddress.getLocalHost().getHostAddress();
		//
		boardModel.setFileName(fileName);
		boardModel.setContent(content);
		boardModel.setRegip(regip);
		//
		boardService.writeArticle(boardModel);
		
		return "redirect:list.do";
	}
	
	@RequestMapping("/commentWrite.do")
	public ModelAndView commentWriteProc(@ModelAttribute("CommentModel") BoardCommentModel commentModel) throws UnknownHostException{
		// new line code change to <br /> tag
		String content = commentModel.getContent().replaceAll("\r\n", "<br />");
		commentModel.setContent(content);
		
		String regip = InetAddress.getLocalHost().getHostAddress();
		commentModel.setRegip(regip);
		//
		boardService.writeComment(commentModel);
		ModelAndView mav = new ModelAndView();
		mav.addObject("idx", commentModel.getLinkedArticleNum());
		mav.setViewName("redirect:view.do");
		
		return mav;
	}
	
	@RequestMapping("/modify.do")
	public ModelAndView boardModify(HttpServletRequest request, HttpSession session){
		String userId = (String) session.getAttribute("userId");
		int idx = Integer.parseInt(request.getParameter("idx"));
		
		BoardModel board = boardService.getOneArticle(idx);
		// <br /> tag change to new line code
		String content = board.getContent().replaceAll("<br />", "\r\n");
		board.setContent(content);
		
		ModelAndView mav = new ModelAndView();
		
		if(!userId.equals(board.getWriterId())){
			mav.addObject("errCode", "1");	// forbidden connection
			mav.addObject("idx", idx);
			mav.setViewName("redirect:view.do");
		} else {
			mav.addObject("board", board);
			mav.setViewName("/board/modify");
		}
		
		return mav;
	}
	
	@RequestMapping(value = "/modify.do", method=RequestMethod.POST)
	public ModelAndView boardModifyProc(@ModelAttribute("BoardModel") BoardModel boardModel, MultipartHttpServletRequest request) throws UnknownHostException{
		String orgFileName = request.getParameter("orgFile");
		MultipartFile newFile = request.getFile("newFile");
		String newFileName = newFile.getOriginalFilename();
		boardModel.setFileName(orgFileName);
		
		// if: when want to change upload file
		if(newFile != null && !newFileName.equals("")){
			if(orgFileName != null || !orgFileName.equals("")){
				// remove uploaded file
				File removeFile = new File(uploadPath  + orgFileName);
				removeFile.delete();
				//
			}
			// create new upload file
			File newUploadFile = new File(uploadPath +newFileName);
			try {
				newFile.transferTo(newUploadFile);
			} catch (Exception e) {
				e.printStackTrace();
			}
			//
			boardModel.setFileName(newFileName);
		}
		//
		// new line code change to <br /> tag
		String content =  boardModel.getContent().replaceAll("\r\n", "<br />");		
		boardModel.setContent(content);
		
		String regip = InetAddress.getLocalHost().getHostAddress();
		boardModel.setRegip(regip);
		//
		
		boardService.modifyArticle(boardModel);
		
		ModelAndView mav = new ModelAndView();
		mav.addObject("idx", boardModel.getIdx());
		mav.setViewName("redirect:/board/view.do");
		return mav;
	}
	
	@RequestMapping("/delete.do")
	public ModelAndView boardDelete(HttpServletRequest request, HttpSession session){
		String userId = (String) session.getAttribute("userId");
		int idx = Integer.parseInt(request.getParameter("idx"));
		
		BoardModel board = boardService.getOneArticle(idx);
		
		ModelAndView mav = new ModelAndView();
		
		if(!userId.equals(board.getWriterId())){
			mav.addObject("errCode", "1");	// it's forbidden connection
			mav.addObject("idx", idx);
			mav.setViewName("redirect:view.do");
		} else {
			List<BoardCommentModel> commentList = boardService.getCommentList(idx); // check comments
			if(commentList.size() > 0){
				mav.addObject("errCode", "2"); // can't delete because a article has comments
				mav.addObject("idx", idx);
				mav.setViewName("redirect:view.do");
			} else {
				// if: when the article has upload file - remove that
				if(board.getFileName() != null){
					File removeFile = new File(uploadPath + board.getFileName());
					removeFile.delete();
				}
				//				
				boardService.deleteArticle(idx);
				
				mav.setViewName("redirect:list.do");
			}
		}		
		return mav;
	}
	
	@RequestMapping("/commentDelete.do")
	public ModelAndView commendDelete(HttpServletRequest request, HttpSession session){
		int idx = Integer.parseInt(request.getParameter("idx"));
		int linkedArticleNum = Integer.parseInt(request.getParameter("linkedArticleNum"));
		
		String userId = (String) session.getAttribute("userId");
		BoardCommentModel comment = boardService.getOneComment(idx);
		
		ModelAndView mav = new ModelAndView();
		
		if(!userId.equals(comment.getWriterId())){
			mav.addObject("errCode", "1");
		} else {
			boardService.deleteComment(idx);
		}		
				
		mav.addObject("idx", linkedArticleNum); // move back to the article
		mav.setViewName("redirect:view.do");
		
		return mav;
	}
	
	@RequestMapping("/recommend.do")
	public ModelAndView updateRecommendcount(HttpServletRequest request, HttpSession session){
		int idx = Integer.parseInt(request.getParameter("idx"));
		String userId = (String) session.getAttribute("userId");
		BoardModel board = boardService.getOneArticle(idx);
		
		ModelAndView mav = new ModelAndView();
		
		if(userId.equals(board.getWriterId())){
			mav.addObject("errCode", "1");
		} else {
			boardService.updateRecommendCount(board.getRecommendcount()+1, idx);
		}
		
		mav.addObject("idx", idx);
		mav.setViewName("redirect:/board/view.do");
		
		return mav;
	}
	
	

	/*@RequestMapping("/fileDownload.do")
	public void fileDownload(HttpServletRequest request, HttpServletResponse response){
		
		// 파일이 저장될 경로.
		String realPath = "D:/folder/workspace/projectName/WebContent/upfile/";
		 
		// 파일 이름이 파라미터로 넘어오지 않으면 리다이렉트 시킨다.
		if(request.getParameter("fileName") == null || "".equals(request.getParameter("fileName"))){
		 
		    response.sendRedirect("/redirect.jsp");
		 
		}else{
		 
		    // 파라미터로 받은 파일 이름.
		    String requestFileNameAndPath = request.getParameter("fileName");
		     
		    // 서버에서 파일찾기 위해 필요한 파일이름(경로를 포함하고 있음)
		    // 한글 이름의 파일도 찾을 수 있도록 하기 위해서 문자셋 지정해서 한글로 바꾼다.
		    String UTF8FileNameAndPath = new String(requestFileNameAndPath.getBytes("8859_1"), "UTF-8");
		     
		    // 파일이름에서 path는 잘라내고 파일명만 추출한다.
		    String UTF8FileName = UTF8FileNameAndPath.substring(UTF8FileNameAndPath.lastIndexOf("/") + 1).substring(UTF8FileNameAndPath.lastIndexOf(File.separator) + 1);
		     
		    // 브라우저가 IE인지 확인할 플래그.
		    boolean MSIE = request.getHeader("user-agent").indexOf("MSIE") != -1;
		     
		    // 파일 다운로드 시 받을 때 저장될 파일명
		    String fileNameToSave = "";
		 
		    // IE,FF 각각 다르게 파일이름을 적용해서 구분해주어야 한다.
		    if(MSIE){
		        // 브라우저가 IE일 경우 저장될 파일 이름
		        // 공백이 '+'로 인코딩된것을 다시 공백으로 바꿔준다.
		        fileNameToSave = URLEncoder.encode(UTF8FileName, "UTF8").replaceAll("\\+", " ");
		    }else{
		        // 브라우저가 IE가 아닐 경우 저장될 파일 이름
		        fileNameToSave = new String(UTF8FileName.getBytes("UTF-8"), "8859_1");
		    }
		 
		    // 다운로드 알림창이 뜨도록 하기 위해서 컨텐트 타입을 8비트 바이너리로 설정한다.
		    response.setContentType("application/octet-stream");
		     
		    // 저장될 파일 이름을 설정한다.
		    response.setHeader("Content-Disposition", "attachment; filename=\"" + fileNameToSave + "\";");
		     
		    // 파일패스 및 파일명을 지정한다.
		    //  String filePathAndName = pageContext.getServletContext().getRealPath("/") + UTF8FileNameAndPath;
		    String filePathAndName = realPath + UTF8FileNameAndPath;
		    File file = new File(filePathAndName);
		     
		    // 버퍼 크기 설정
		    byte bytestream[] = new byte[2048000];
		 
		    // response out에 파일 내용을 출력한다.
		    if (file.isFile() && file.length() > 0){
		         
		        FileInputStream fis = new FileInputStream(file);
		        BufferedInputStream bis = new BufferedInputStream(fis);
		        BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
		             
		        int read = 0;
		             
		        while ((read = bis.read(bytestream)) != -1){
		            bos.write(bytestream , 0, read);
		        }
		         
		        bos.close();
		        bis.close();
		         
		    }
		 
		}
		
	}*/
	@RequestMapping(value = "/first.do", method = RequestMethod.GET)
	public String main(HttpServletRequest request, HttpServletResponse response) {
		
		return "/board/first";
	}


	

	@RequestMapping("/fileDownload.do")
	public void fileDownload(HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		// 파일 이름이 파라미터로 넘어오지 않으면 리다이렉트 시킨다.
		if (request.getParameter("fileName") == null
				|| "".equals(request.getParameter("fileName"))) {

			PrintWriter out = response.getWriter();
			out.print("<script>alert('error'); self.close();</script>");

		} else {

			// 파라미터로 받은 파일 이름.
			String requestFileNameAndPath = uploadPath + File.separator
					+ request.getParameter("fileName");

			// 서버에서 파일찾기 위해 필요한 파일이름(경로를 포함하고 있음)
			// 한글 이름의 파일도 찾을 수 있도록 하기 위해서 문자셋 지정해서 한글로 바꾼다.
			String UTF8FileNameAndPath = new String(
					requestFileNameAndPath.getBytes("8859_1"), "UTF-8");

			// 파일이름에서 path는 잘라내고 파일명만 추출한다.
			String UTF8FileName = UTF8FileNameAndPath.substring(
					UTF8FileNameAndPath.lastIndexOf("/") + 1).substring(
					UTF8FileNameAndPath.lastIndexOf(File.separator) + 1);

			// 브라우저가 IE인지 확인할 플래그.
			boolean MSIE = request.getHeader("user-agent").indexOf("MSIE") != -1;

			// 파일 다운로드 시 받을 때 저장될 파일명
			String fileNameToSave = "";

			// IE,FF 각각 다르게 파일이름을 적용해서 구분해주어야 한다.
			if (MSIE) {
				// 브라우저가 IE일 경우 저장될 파일 이름
				// 공백이 '+'로 인코딩된것을 다시 공백으로 바꿔준다.
				fileNameToSave = URLEncoder.encode(UTF8FileName, "UTF8")
						.replaceAll("\\+", " ");
			} else {
				// 브라우저가 IE가 아닐 경우 저장될 파일 이름
				fileNameToSave = new String(UTF8FileName.getBytes("UTF-8"),
						"8859_1");
			}

			// 다운로드 알림창이 뜨도록 하기 위해서 컨텐트 타입을 8비트 바이너리로 설정한다.
			response.setContentType("application/octet-stream");

			// 저장될 파일 이름을 설정한다.
			response.setHeader("Content-Disposition", "attachment; filename=\""
					+ fileNameToSave + "\";");
			// 파일패스 및 파일명을 지정한다.
			// String filePathAndName =
			// pageContext.getServletContext().getRealPath("/") +
			// UTF8FileNameAndPath;
			String filePathAndName = UTF8FileNameAndPath;
			File file = new File(filePathAndName);
			// 버퍼 크기 설정
			byte bytestream[] = new byte[2048000];
			// response out에 파일 내용을 출력한다.
			if (file.isFile() && file.length() > 0) {
				FileInputStream fis = new FileInputStream(file);
				BufferedInputStream bis = new BufferedInputStream(fis);
				BufferedOutputStream bos = new BufferedOutputStream(
						response.getOutputStream());
				int read = 0;
				while ((read = bis.read(bytestream)) != -1) {
					bos.write(bytestream, 0, read);
				}
				bos.close();
				bis.close();
			}
		}
	}
}
